#include <buola/widgets/cfilelist.h>

#include <buola/io/cfolder.h>
#include <buola/gui/cpropertyfield.h>
#include <buola/gui/cclipboard.h>
#include <buola/io/cfilefilter.h>
#include <buola/gui/cmenu.h>

#include "cfilelistfiller.h"

#define ID_FIELD_URI        2
#define ID_FIELD_INTERFACE  3
#define ID_FIELD_SIZE       4
#define ID_FIELD_TYPE       5

#define FILL_NONE           0
#define FILL_NORMAL         1
#define FILL_WILLFILL       2
#define FILL_FILLING        3
#define FILL_CANCEL         4

namespace buola { namespace gui {

CFileList::CFileList()
{
    SetStyle(CListBox::STYLE_ARRAYVIEW|CListBox::STYLE_MULTIPLE|CListBox::STYLE_ICONMENU|CListBox::STYLE_VIEWMENU|
             CListBox::STYLE_DRAGNDROP|CListBox::STYLE_EDITABLE);

    mFiller=nullptr;
    mFillerID=-1;

    mCreatingFolderItem=nullptr;

    AddField(new CPropertyField(L"uri",L"Full name",WI18N("Full name"),nullptr,CPropertyField::PLF_HIDDEN),ID_FIELD_URI);
    AddField(new CPropertyField(L"pointer",L"interface",WI18N("Interface"),nullptr,CPropertyField::PLF_HIDDEN),ID_FIELD_INTERFACE);
    AddField(new CPropertyField(L"filesize",L"size",WI18N("Size")),ID_FIELD_SIZE);
    AddField(new CPropertyField(L"string",L"type",WI18N("Type")),ID_FIELD_TYPE);
    FillList();
}

CFileList::~CFileList()
{
    if(mFiller)
    {
        mFiller->Cancel();
    }
}

io::CURI CFileList::GetURI(CListBox::SItem *pItem)
{
    return pItem->Value(ID_FIELD_URI).Get<io::CURI>();
}

io::CFile CFileList::GetSelectedFile()
{
    CListBox::SItem *lItem=GetSelItem();

    if(!lItem) return io::CFile();
    return GetFile(lItem);
}

void CFileList::CreateFolder(const std::wstring &pName)
{
    CListBox::SItem *lItem=NewItem(pName,CIcon::Get("folder"));
    lItem->Value(ID_FIELD_INTERFACE).Set<io::CFile>(io::CFile());

    mCreatingFolderItem=lItem;
    AddItem(lItem);
    StartEditing(lItem);
}

io::CFile CFileList::GetFile(CListBox::SItem *pItem)
{
    return pItem->Value(ID_FIELD_INTERFACE).Get<io::CFile>();
}

void CFileList::SetFilter(io::PFileFilter pFilter)
{
    if(mFilter==pFilter) return;
    mFilter=pFilter;

    FillList();
}

void CFileList::SetURI(const io::CURI &pURI)
{
    if(mURI==pURI) return;
    mURI=pURI;
    mFolder=io::CFolder(mURI);

    FillList();
}

void CFileList::FillList()
{
    if(mURI.empty()) return;

    if(mFiller)
    {
        mFiller->Cancel();
    }

    mFiller=new CFileListFiller(this,mURI);
    mFillerID=mFiller->GetID();
    mFiller->eAdd.Connect(&CFileList::OnFillerAdd,this,_1,_2,_3,mFillerID);
    mFiller->eRemove.Connect(&CFileList::OnFillerRemove,this,_1,mFillerID);
    mFiller->Start();

    RemoveAllItems();
}

void CFileList::OnFillMenu(PMenu pMenu,bool pFile)
{
    if(pFile)
    {
        /*
        io::CFile lFile=GetFile(GetSelItem());
        if(mFile!=lFile)
        {
            if(mInterface)
            {
                //TODO:Should remove connection from previous interface
            }
            mInterface=lInterface;
            mInterface->eMustUpdate.Connect(&CFileList::FillList,this);
            mInterface->eIntAction.Connect(&CFileList::OnIntAction,this,_1,
                                                mInterface.get());
            mInterface->sFillActions.Connect(sFillActions);
            mInterface->sExtAction.Connect(sExtAction);
        }
        mInterface->FillMenu(pMenu);
        */
        ///\todo
    }
}

void CFileList::OnDragDrag(CDrag *pDrag,CClipboard *pCB)
{
    pCB->SetURI(GetURI(GetSelItem()));
}

void CFileList::OnItemRemoved(CListBox::SItem *pItem)
{
    CListBox::OnItemRemoved(pItem);

    if(pItem==mCreatingFolderItem) return;

    io::CFile lFile=GetFile(pItem);
    ///\todo
    /*
    if(lInterface==mInterface)
    {
        //TODO:Should remove connection from previous interface
        mInterface=nullptr;
    }
    */
}

void CFileList::OnItemDblClk(CListBox::SItem *pItem)
{
    io::CFile lFile=GetFile(pItem);
    ///\todo
    /*
    if(lInterface!=mInterface)
    {
        if(mInterface)
        {
            //TODO:Should remove connection from previous interface
        }
        mInterface=lInterface;
        mInterface->eMustUpdate.Connect(&CFileList::FillList,this);
        mInterface->eIntAction.Connect(&CFileList::OnIntAction,this,_1,
                                                mInterface.get());
        mInterface->sFillActions.Connect(sFillActions);
        mInterface->sExtAction.Connect(sExtAction);
    }
    mInterface->DoDefaultAction();
    */
}

void CFileList::OnItemChanged(CListBox::SItem *pItem)
{
    CListBox::OnItemChanged(pItem);

    if(pItem==mCreatingFolderItem)
    {
        if(pItem->GetText().empty())
        {
            RemoveItemByID(mCreatingFolderItem->mID);
            Refresh();
        }
        else
        {
            ///\todo
            //mFolder.MkDir(utf8(pItem->GetText()));
        }
        mCreatingFolderItem=nullptr;
    }
}

void CFileList::OnIntAction(TID pAction,const io::CFile &pFile)
{
//    if(pInterface!=mInterface) return;
//    eIntAction(pAction,pInterface->GetFile()->GetURI());
}

void CFileList::OnFillerAdd(int pCount,CListBox::SItem **pItems,bool pCreatingLater,TID pID)
{
    if(pID==mFillerID)  //It's the current filler... process
    {
//      SetAutoUpdate(false);
        for(int i=0;i<pCount;i++)
        {
            if(pCreatingLater)
            {
                bool lFound=false;
                for(int j=0;j<mLWI.size();j++)
                {
                    if(mLWI[j]->GetText()==pItems[i]->GetText())
                    {
                        lFound=true;
                        ReplaceItem(mLWI[j],pItems[i]);
                        break;
                    }
                }
                if(lFound) continue;
            }

            AddItem(pItems[i]);
        }
//      SetAutoUpdate(true);
//      Update();
    }
    else
    {
        for(int i=0;i<pCount;i++)
        {
            delete pItems[i];
        }
    }

    delete[] pItems;
}

void CFileList::OnFillerRemove(const std::wstring &pName,TID pID)
{
    if(pID==mFillerID)
    {
        CListBox::SItem *lItem=FindItem(pName);
        if(!lItem)
        {
            msg_warn() << "Item to remove not found\n";
            return;
        }

        RemoveItemByID(lItem->mID);
        Update();
    }
}

/*namespace gui*/ } /*namespace buola*/ }
